package deanandjames.sound;

import javax.sound.sampled.*;
import java.io.IOException;
import java.text.DecimalFormat;

public class SoundInfo implements LineListener {
	private final static String SOUND_DIR = "Sounds/";
	private Clip clip = null;
	private final DecimalFormat decimalFormat;
	private final String fileName;
	private boolean isLooping = false;
	private final String name;
	private SoundWatcher watcher = null;

	public SoundInfo(String name, String fileName) {
		this.name = name;
		this.fileName = SOUND_DIR + fileName;
		decimalFormat = new DecimalFormat("0.#");
		loadClip();
	}

	public void close() {
		if (clip != null) {
			clip.stop();
			clip.close();
		}
	}

	public void pause() {
		if (clip != null) {
			clip.stop();
		}
	}

	public void play(boolean toLoop) {
		if (clip != null) {
			isLooping = toLoop;
			clip.start();
		}
	}

	public void resume() {
		if (clip != null) {
			clip.start();
		}
	}

	public void setWatcher(SoundWatcher sw) {
		watcher = sw;
	}

	public void stop() {
		if (clip != null) {
			isLooping = false;
			clip.stop();
			clip.setFramePosition(0);
		}
	}

	public void update(LineEvent lineEvent) {
		if (lineEvent.getType() == LineEvent.Type.STOP) {
			clip.stop();
			clip.setFramePosition(0);
			if (!isLooping) {
				if (watcher != null) {
					watcher.atSequenceEnd(name, SoundWatcher.STOPPED);
				}
			} else {
				clip.start();
				if (watcher != null) {
					watcher.atSequenceEnd(name, SoundWatcher.REPLAYED);
				}
			}
		}
	}

	private void checkDuration() {
		final double duration = clip.getMicrosecondLength() / 1000000.0;
		if (duration <= 1.0) {
			System.out.println("WARNING. Duration <= 1 sec : " + decimalFormat.format(duration) + " secs");
			System.out.println("         The clip in " + fileName + " may not play in J2SE 1.5 -- make it longer");
		} else {
			System.out.println(fileName + ": Duration: " + decimalFormat.format(duration) + " secs");
		}
	}

	private void loadClip() {
		try {
			AudioInputStream stream = AudioSystem.getAudioInputStream(getClass().getResource(fileName));
			AudioFormat format = stream.getFormat();
			if (format.getEncoding() == AudioFormat.Encoding.ULAW || format.getEncoding() == AudioFormat.Encoding.ALAW) {
				final AudioFormat newFormat = new AudioFormat(AudioFormat.Encoding.PCM_SIGNED, format.getSampleRate(), format.getSampleSizeInBits() * 2, format.getChannels(), format.getFrameSize() * 2, format.getFrameRate(), true);
				stream = AudioSystem.getAudioInputStream(newFormat, stream);
				System.out.println("Converted Audio format: " + newFormat);
				format = newFormat;
			}
			final DataLine.Info info = new DataLine.Info(Clip.class, format);
			if (!AudioSystem.isLineSupported(info)) {
				System.out.println("Unsupported Clip File: " + fileName);
				return;
			}
			clip = (Clip) AudioSystem.getLine(info);
			clip.addLineListener(this);
			clip.open(stream);
			stream.close();
			checkDuration();
		} catch (final UnsupportedAudioFileException audioException) {
			System.out.println("Unsupported audio file: " + fileName);
		} catch (final LineUnavailableException noLineException) {
			System.out.println("No audio line available for : " + fileName);
		} catch (final IOException ioException) {
			System.out.println("Could not read: " + fileName);
		} catch (final Exception e) {
			System.out.println("Problem with " + fileName);
		}
	}
}
